/*
This file is part of Caelum.
See http://www.ogre3d.org/wiki/index.php/Caelum 

Copyright (c) 2008 Caelum team. See Contributors.txt for details.

Caelum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Caelum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Caelum. If not, see <http://www.gnu.org/licenses/>.
*/

#include "CaelumPrecompiled.h"
#include "SkyLight.h"

using namespace Caelum;
using namespace Ogre;

const Ogre::Real BaseSkyLight::DEFAULT_AUTO_DISABLE_THRESHOLD = 0.1f;


//-----------------------------------------------------------------------------
/// Constructor
BaseSkyLight::BaseSkyLight (Ogre::SceneManager *sceneMgr, Ogre::SceneNode *caelumRootNode) :
mMainLight           (NULL),                          // The main directional light.
mNode                (NULL),                          // The sun scene node.
mRadius              (0.f),                           // Base distance of the light.
mDirection           (Vector3::ZERO),                 // The latest normalised sun direction.
mBodyColour          (ColourValue::White),            // Body sphere colour, as set by setBodyColour
mLightColour         (ColourValue::White),            // Sun light colour, as set by setLightColour
mDiffuseMultiplier   (ColourValue(1.f, 1.f, 0.9f)),   // Colour multiplier for light diffuse colour.
mSpecularMultiplier  (ColourValue(1.f, 1.f, 1.f)),    // Colour multiplier for light specular colour.
mAmbientMultiplier   (ColourValue(0.2f, 0.2f, 0.2f)), // Colour multiplier for ambient light colour. No effect, this value is only stored here.
mAutoDisableThreshold(DEFAULT_AUTO_DISABLE_THRESHOLD),// Threshold beneath which the light is automatically disabled.
mAutoDisableLight    (false),                         // If the light is automatically disabled beneath mAutoDisableThreshold
mForceDisableLight   (false)                          // If the light is always disabled. Separate from the mAutoDisable mechanism.
{
   assert(sceneMgr && caelumRootNode && "Invalid construcors args. BaseSkyLight::BaseSkyLight");

   mNode = caelumRootNode->createChildSceneNode();

   // Generate ligth unique name
   Ogre::String lightName = "CaelumSkyLight" + Ogre::StringConverter::toString((size_t)this);
   mMainLight = sceneMgr->createLight(lightName);
   mMainLight->setType(Ogre::Light::LT_DIRECTIONAL);
   sceneMgr->getRenderQueue()->getQueueGroup(CAELUM_RENDER_QUEUE_SUN)->setShadowsEnabled(false);
}


//-----------------------------------------------------------------------------
/// Destructor
BaseSkyLight::~BaseSkyLight()
{
   if (mNode->getParent())
      mNode->getParentSceneNode()->removeAndDestroyChild(mNode->getName());
   else
      mNode->getCreator()->destroySceneNode(mNode);

   mMainLight->_getManager()->destroyLight (mMainLight);
   // m2codeGEN: what about
   // sceneMgr->getRenderQueue()->getQueueGroup(CAELUM_RENDER_QUEUE_SUN)->setShadowsEnabled(false);
}


//-----------------------------------------------------------------------------
/// 
void BaseSkyLight::setFarRadius(Ogre::Real radius)
{
   CameraBoundElement::setFarRadius(radius);
   mRadius = radius;
}

//-----------------------------------------------------------------------------
///
void BaseSkyLight::update(const Vector3 &direction, const ColourValue &lightColour, const ColourValue &bodyColour)
{
   setLightDirection(direction);
   setLightColour(lightColour);
   setBodyColour(bodyColour);
}


//-----------------------------------------------------------------------------
///
void BaseSkyLight::setLightDirection (const Ogre::Vector3 &dir)
{
   mDirection = dir;
   mMainLight->setDirection (mNode->_getDerivedOrientation() * dir);
}


//-----------------------------------------------------------------------------
///
void BaseSkyLight::setLightColour (const Ogre::ColourValue &colour)
{
   mLightColour = colour;        // Store this last colour
   setMainLightColour(colour);   // Apply change
}


//-----------------------------------------------------------------------------
/// Temporary change main light color
void BaseSkyLight::setMainLightColour (const Ogre::ColourValue &colour)
{
   // Set light colours.
   if (shouldEnableLight(colour))
   {
      mMainLight->setVisible(true);
      mMainLight->setDiffuseColour(colour * mDiffuseMultiplier);
      mMainLight->setSpecularColour(colour * mSpecularMultiplier);
   }
   else
      mMainLight->setVisible(false);
}


//-----------------------------------------------------------------------------
/// If the light should be enabled for a certain value
bool BaseSkyLight::shouldEnableLight(const Ogre::ColourValue &colour)
{
   if (mForceDisableLight)
      return false;
   else if (mAutoDisableLight)
   {
      Ogre::Real sum = colour.r + colour.g + colour.b;
      return sum >= mAutoDisableThreshold;
   }
   else
      return true;
}
